/*
 * Copyright 2022-2023 the original author(https://github.com/wj596)
 * 
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */
package org.jsets.fastboot.security.captcha;

import org.jsets.fastboot.util.IoUtils;
import org.jsets.fastboot.util.StringUtils;
import org.jsets.fastboot.security.ICaptchaProvider;
import org.jsets.fastboot.security.cache.Cache;
import org.jsets.fastboot.security.cache.ICacheManager;
import org.jsets.fastboot.security.config.SecurityProperties;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Objects;
import java.util.Properties;
import javax.imageio.ImageIO;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import lombok.extern.slf4j.Slf4j;

/**
 * 验证码实现
 *
 * @author wangjie (https://github.com/wj596)
 * @date 2021.07.05 14:48
 * @since 0.1
 */
@Slf4j
public class CaptchaProviderImpl implements ICaptchaProvider {

	private final Cache cache;
	private final SecurityProperties properties;
	private Producer producer;
	
	public CaptchaProviderImpl(SecurityProperties properties, ICacheManager cacheManager) {
		this.properties = properties;
		this.cache = cacheManager.create(this.properties.getCaptchaCacheName());
		this.buildProducer();
		log.info("CaptchaProviderImpl初始化完成");
	}

	protected void buildProducer() {
		DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
		Properties properties = new Properties();
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体,楷体,微软雅黑");
        properties.setProperty(Constants.KAPTCHA_BORDER, "no");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        this.producer = defaultKaptcha;
	}
	
	@Override
	public Base64CaptchaResult generateBase64Captcha() {
		String captchaKey = StringUtils.getUUID();
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		try {
			String text = this.producer.createText();
			BufferedImage image = this.producer.createImage(text);
			ImageIO.write(image, "jpeg", stream);
			String captchaImageBase64 = "data:image/jpeg;base64," + Base64.getEncoder().encodeToString(stream.toByteArray());
			Base64CaptchaResult result = new Base64CaptchaResult();
			result.setCaptchaKey(captchaKey);
			result.setCaptchaImageBase64(captchaImageBase64);
			this.cache.put(captchaKey, text, this.properties.getCaptchaCacheTimeout());
			return result;
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		} finally {
			IoUtils.closeQuietly(stream);
		}
	}

	@Override
	public CaptchaValidateResult validateCaptcha(String captchaKey, String captcha) {
		Object value = this.cache.get(captchaKey);
		if (Objects.isNull(value)) {
			return CaptchaValidateResult.TIMEOUT;
		}
		String stub = (String) value;
		boolean result = stub.equals(captcha);
		this.cache.delete(captchaKey);
		if (result) {
			return CaptchaValidateResult.OK;
		}
		return CaptchaValidateResult.INVALID;
	}

}